package vip.liux.backend.application.serviceImpl.files;

import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import vip.liux.application.dots.ListResultDto;
import vip.liux.application.dots.PagedResultDto;
import vip.liux.backend.application.service.files.AutoMapperProfile;
import vip.liux.backend.application.service.files.DirectoryDescriptorAppService;
import vip.liux.backend.application.service.files.dtos.*;
import vip.liux.contracts.models.files.*;
import vip.liux.contracts.repositories.files.DirectoryDescriptorRepository;
import vip.liux.contracts.repositories.files.FileDescriptorRepository;
import vip.liux.contracts.shared.properties.FilesProperties;
import vip.liux.contracts.shared.value.LevelModel;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static vip.liux.application.PageKit.toSort;

@Service
public class DirectoryDescriptorAppServiceImpl implements DirectoryDescriptorAppService {
    protected final DirectoryManager directoryManager;

    protected final DirectoryDescriptorRepository directoryDescriptorRepository;

    protected final FileManager fileManager;

    protected final FileDescriptorRepository fileDescriptorRepository;

    protected final FilesProperties filesProperties;

    public DirectoryDescriptorAppServiceImpl(DirectoryManager directoryManager, DirectoryDescriptorRepository directoryDescriptorRepository, FileManager fileManager, FileDescriptorRepository fileDescriptorRepository, FilesProperties filesProperties) {
        this.directoryManager = directoryManager;
        this.directoryDescriptorRepository = directoryDescriptorRepository;
        this.fileManager = fileManager;
        this.fileDescriptorRepository = fileDescriptorRepository;
        this.filesProperties = filesProperties;
    }

    /**
     * 根据ID获取目录描述符
     *
     * @param id 目录ID
     * @return 目录描述符
     */
    @Override
    public DirectoryDescriptorDto get(Long id) {
        DirectoryDescriptor descriptor = directoryDescriptorRepository.findById(id)
                .orElseThrow(DirectoryNotExistException::new);
        return AutoMapperProfile.INSTANCE.toDirectoryDescriptorDto(descriptor);
    }

    /**
     * 获取父目录下的目录描述符列表
     *
     * @param parentId 父目录ID
     * @return 目录描述符列表
     */
    @Override
    public ListResultDto<DirectoryDescriptorInfoDto> getList(Long parentId) {
        List<DirectoryDescriptor> subDirectories = directoryDescriptorRepository.getAllChildren(parentId);
        List<DirectoryDescriptorInfoDto> result = new ArrayList<>();

        for (DirectoryDescriptor subDirectory : subDirectories) {
            DirectoryDescriptorInfoDto dto = new DirectoryDescriptorInfoDto(
                    subDirectory.getId(), subDirectory.getName(),
                    subDirectory.getParentId(),
                    directoryManager.existsByParentId(subDirectory.getId(), false));
            result.add(dto);
        }

        return new ListResultDto<>(result);
    }

    @Override
    public ListResultDto<DirectoryDescriptorInfoDto> getTreeList(Long parentId) {
        ListResultDto<DirectoryDescriptorInfoDto> resultDto = getList(parentId);
        List<DirectoryDescriptorInfoDto> list = LevelModel.buildTree(resultDto.getItems(),
                DirectoryDescriptorInfoDto::getId,
                DirectoryDescriptorInfoDto::getParentId);
        return new ListResultDto<>(list);
    }

    /**
     * 创建目录
     *
     * @param input 创建目录输入
     * @return 创建的目录描述符
     */
    @Override
    public DirectoryDescriptorDto create(CreateDirectoryInput input) {

        DirectoryDescriptor directoryDescriptor = directoryManager.create(input.name(), input.parentId(), null);

        directoryDescriptorRepository.save(directoryDescriptor);

        return AutoMapperProfile.INSTANCE.toDirectoryDescriptorDto(directoryDescriptor);
    }

    /**
     * 重命名目录
     *
     * @param id    目录ID
     * @param input 重命名输入
     * @return 重命名后的目录描述符
     */
    @Override
    public DirectoryDescriptorDto rename(Long id, RenameDirectoryInput input) {
        DirectoryDescriptor directory = directoryDescriptorRepository.findById(id)
                .orElseThrow(DirectoryNotExistException::new);

        directoryManager.rename(directory, input.name());

        directoryDescriptorRepository.save(directory);

        return AutoMapperProfile.INSTANCE.toDirectoryDescriptorDto(directory);
    }

    /**
     * 获取目录详情
     *
     * @param parentId 父目录ID
     * @param name     目录名称
     * @return 目录描述符详情
     */
    @Override
    public DirectoryDescriptorDto detail(Long parentId, String name) {
        DirectoryDescriptor detail = directoryDescriptorRepository.findByName(name, parentId);
        return Optional.ofNullable(detail).map(AutoMapperProfile.INSTANCE::toDirectoryDescriptorDto).orElse(null);
    }

    /**
     * 获取目录内容
     *
     * @param input 目录内容请求输入
     * @return 目录内容分页结果
     */
    @Override
    public PagedResultDto<DirectoryContentDto> getContent(DirectoryContentRequestInput input) {

        Sort sort = toSort(input.getSorting());

        List<DirectoryDescriptor> subDirectories = directoryDescriptorRepository.getChildren(input.getId(), input.getFilter(), sort);

        List<DirectoryContentDto> result = new ArrayList<>(subDirectories.stream()
                .map(subDirectory -> new DirectoryContentDto(
                        subDirectory.getName(), true, subDirectory.getId(), 0, null))
                .toList());

        List<FileDescriptor> subFiles = fileDescriptorRepository.getList(input.getId(), input.getFilter(), sort);

        result.addAll(subFiles.stream().map(file -> new DirectoryContentDto(
                file.getName(), false, file.getId(), file.getSize(), filesProperties.getIcon().getFileIconInfo(file.getName()))).toList());

        var subDirectoryCount = directoryDescriptorRepository.getChildrenCount(input.getId());
        var subFileCount = fileDescriptorRepository.countDirectoryFiles(input.getId());

        return new PagedResultDto<>(result, subDirectoryCount + subFileCount);
    }

    /**
     * 删除目录
     *
     * @param id 目录ID
     */
    @Override
    public void delete(Long id) {
        directoryManager.delete(id);
    }

    /**
     * 移动目录
     *
     * @param input 移动目录输入
     * @return 移动后的目录描述符
     */
    @Override
    public DirectoryDescriptorDto move(MoveDirectoryInput input) {
        DirectoryDescriptor directory = directoryDescriptorRepository.findById(input.id())
                .orElseThrow(DirectoryNotExistException::new);

        directoryManager.move(directory, input.newParentId());

        directoryDescriptorRepository.save(directory);
        return AutoMapperProfile.INSTANCE.toDirectoryDescriptorDto(directory);
    }
}
